﻿using DingChiServiceApp.helper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DingChiServiceApp
{
    /// <summary>
    /// 数据库存的帮助类
    /// </summary>
    public abstract class DbHelper
    {
        /// <summary>
        /// 是否开启调试模式 默认 false
        /// </summary>
        public static bool isDebug = false;
        /// <summary>
        /// 是否开启错误日志 默认 true ,当发生错误时，会在运行目录下面的 /log/ 下面 sqlDao*.txt.中记录信息
        /// </summary>
        public static bool enableErrorLog = true;
        /// <summary>
        /// 连接字符串
        /// </summary>
        public string connectionString = string.Empty;
        /// <summary>
        /// 是否正在连接
        /// </summary>
        /// <returns></returns>
        public abstract Boolean IsConnecting();
        /// <summary>
        /// 连接是否已经打开
        /// </summary>
        /// <returns></returns>
        public abstract Boolean IsOpened();

        /// <summary>
        /// 统计条数
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="condition">条件</param>
        /// <returns></returns>
        public abstract int Count(string tableName, string condition);

        /// <summary>
        /// 根据Id查找对像
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns> 对像  or null</returns>
        public abstract T FindById<T>(int id) where T : class, new();

        /// <summary>
        /// 按sql语句查询
        /// </summary>
        /// <param name="sql">sql语句查询</param>
        /// <returns>List</returns>
        public abstract List<T> Select<T>(string sql) where T : class, new();

        /// <summary>
        /// 按sql语句查询 一条数据
        /// </summary>
        /// <param name="sql">sql语句查询</param>
        /// <returns>T</returns>
        public abstract T Find<T>(string sql) where T : class, new();
        /// <summary>
        /// 检查对像是已经存在于数据库中
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public abstract bool CheckExist<T>(T obj);
        /// <summary>
        /// 执行 sql 语句，返回 DataTable
        /// </summary>
        /// <param name="sql"> sql 语句</param>
        /// <returns> DataTable </returns>
        public abstract DataTable ExcuteDataTable(string sql);
        /// <summary>
        /// 检查连接能否打开
        /// </summary>
        /// <param name="connstring">连接字符串</param>
        /// <returns>true  or false</returns>
        public abstract bool CheckConn(string connstring);

        /// <summary>
        /// judge the table is or not exist 表是否存在
        /// </summary>
        /// <param name="dbName">库名</param>
        /// <param name="table">表名</param>
        /// <returns></returns>
        public abstract bool ExistTable(string dbName, string table);

    
        /// <summary>
        /// get the all table's name of in the database
        /// </summary>
        /// <returns></returns>
       // public abstract string[] GetAllTableName(string dbname);

        /// <summary>
        /// 获取数据库中所有表的结构
        /// </summary>
        /// <typeparam name="T"> TableScema和子类</typeparam>
        /// <param name="dbname">库名</param>
        /// <returns></returns>
       // public abstract List<T> GetAllTableSchema<T>(string dbname);

        /// <summary>
        /// get the schema of table
        /// </summary>
        /// <param name="tableName"></param>
        /// <returns></returns>    
        public abstract string GetCreateSql(string tableName);

        /// <summary>
        /// 删除对像 ，支持软件删除
        /// </summary>
        /// <typeparam name="T">对像类型</typeparam>
        /// <param name="obj">对像</param>
        /// <param name="isTrueDelete">是否真的删除 默认软删除</param>
        /// <returns>影响行数</returns>
        public abstract int Delete<T>(T obj, Boolean isTrueDelete = false);
        /// <summary>
        /// 删除操作
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public abstract int Delete(string sql);
        /// <summary>
        /// 执行修改语句
        /// </summary>
        /// <param name="sql">删除语句</param>
        /// <returns>影响行数</returns>
        public abstract int Update(string sql);

        /// <summary>
        /// 修改对像
        /// </summary>
        /// <typeparam name="T">对像类型</typeparam>
        /// <param name="obj">对像</param>
        /// <returns>影响行数</returns>
        public abstract int Update<T>(T obj);


        /// <summary>
        /// 执行插入语句
        /// </summary>
        /// <param name="sql">插入语句</param>
        /// <returns>影响行数</returns>
        public abstract int Insert(string sql);

        /// <summary>
        /// 插入对像
        /// </summary>
        /// <typeparam name="T">对像类型</typeparam>
        /// <param name="obj">对像</param>
        /// <returns>影响行数</returns>
        public abstract int Insert<T>(T obj);

        /// <summary>
        /// 插入或者更新对像
        /// </summary>
        /// <typeparam name="T">对像类型</typeparam>
        /// <param name="obj">对像</param>
        /// <returns>影响行数</returns>
        public abstract int InsertOrUpdate<T>(T obj);

        /// <summary>
        /// 事务处理多条多条操作
        /// </summary>
        /// <param name="sqls"></param>
        /// <returns></returns>
        public abstract int TransactionExecute(string[] sqls);


        /// <summary>
        /// 将数据解析为对像,并记录日志
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="row">Data Row</param>
        /// <param name="fArray"> 类型的属性集合，不传会根据 T 的类型获取</param>
        /// <returns></returns>
        protected T ParseEntityWithLog<T>(DataRow row, FieldInfo[] fArray = null) where T : class, new()
        {
            string msg = String.Empty;
            try
            {
                T entity = new T();
                if (fArray == null)
                {
                    fArray = entity.GetType().GetFields();
                }
                msg = "type: " + entity.GetType().Name + "\n";
                foreach (FieldInfo filedInfo in fArray)
                {
                    msg += "\t FieldInfo : Name:" + filedInfo.Name + " FieldType:" + filedInfo.FieldType + " ";
                    //min camel
                    string columnName = StringHelper.LowerCaseFirstLetter(filedInfo.Name);
                    if (row.Table.Columns.Contains(columnName))
                    {
                        var value = row[columnName];
                        msg += "  DB column value type: " + value.GetType().Name + " Value: " + value + " \n";
                        if (value is DBNull)
                        {
                            filedInfo.SetValue(entity, null);
                            continue;
                        }
                        else if (value is DateTime dateTime)
                        {

                            if (filedInfo.FieldType.Equals(typeof(DateTime)))
                            {
                                filedInfo.SetValue(entity, value);
                            }
                            else if (filedInfo.FieldType.Equals(typeof(String)))
                            {
                                filedInfo.SetValue(entity, dateTime.ToString("yyyy-MM-dd HH:mm:ss"));
                            }
                            else if (filedInfo.FieldType.Equals(typeof(Int64)))
                            {
                                filedInfo.SetValue(entity, Convert.ToInt64(value));
                            }
                            else if (filedInfo.GetType().Equals(typeof(Int32)))
                            {
                                filedInfo.SetValue(entity, Convert.ToInt32(value));
                            }
                            else if (filedInfo.GetType().Equals(typeof(Int16)))
                            {
                                filedInfo.SetValue(entity, Convert.ToInt16(value));
                            }
                            else
                            {
                                filedInfo.SetValue(entity, value);
                            }
                        }
                        else if (value is UInt64 u64Value)
                        {
                            filedInfo.SetValue(entity, Convert.ToInt64(u64Value));
                        }
                        else if (value is UInt32 u32Value)
                        {
                            filedInfo.SetValue(entity, Convert.ToInt32(u32Value));
                        }
                        else if (value is UInt16 u16Value)
                        {
                            filedInfo.SetValue(entity, Convert.ToInt64(u16Value));
                        }
                        else if (value is SByte sb)
                        {
                            if (filedInfo.FieldType == typeof(Nullable<Boolean>) || filedInfo.FieldType == typeof(Boolean))
                            {
                                filedInfo.SetValue(entity, sb > 0);
                            }
                            else if (filedInfo.FieldType is Int16 || filedInfo.FieldType == typeof(Nullable<Int16>))
                            {
                                filedInfo.SetValue(entity, Convert.ToInt16(sb));
                            }
                            else if (filedInfo.FieldType is Int32 || filedInfo.FieldType == typeof(Nullable<Int32>))
                            {
                                filedInfo.SetValue(entity, Convert.ToInt32(sb));
                            }
                            else
                            {
                                filedInfo.SetValue(entity, sb);
                            }
                        }
                        else
                        {
                            if (filedInfo.FieldType == typeof(string))
                            {
                                filedInfo.SetValue(entity, value.ToString());
                            }
                            else
                            {
                                filedInfo.SetValue(entity, value);
                            }
                        }
                    }
                }
                return entity;
            }
            catch (Exception ex)
            {
                if (string.IsNullOrEmpty(msg))
                {
                    SaveErrorLog(ex.Message);
                }
                else
                {
                    string m = ex.Message + " 信息：" + msg;
                    SaveErrorLog(m);
                }
                throw ex;
            }
        }

        public void PrintSql(String sql)
        {
            if (isDebug)
            {
                Debug.WriteLine("======================================");
                Debug.WriteLine("SQL:" + sql);
                Debug.WriteLine("======================================");
            }
        }

        public void SaveErrorLog(String msg)
        {
            if (enableErrorLog)
            {
                LogHelper.FileLog(msg);
            }
        }

        /// <summary>
        /// 执行sql 
        /// </summary>
        /// <returns>影响行数</returns>
        public abstract int ExecuteNonQuery(string sql);

        /// <summary>
        /// 数据库存是否存在
        /// </summary>
        /// <param name="databaseName">名称</param>
        /// <returns></returns>
        public abstract bool ExistDatabase(string databaseName);

        /// <summary>
        /// 创建数据库
        /// </summary>
        /// <param name="databaseName">名称</param>
        /// <returns></returns>
        public abstract bool CreateDatabase(string databaseName);
    }
}
